In [47]:
## STAT 415/615 Regression (M. Baron)

## Python Lab 3. Univariate Linear Regression

import os
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.api as sm

# Set the working directory. Yours will be different from mine. It should be the folder where you saved the data file from Blackboard.

os.chdir(r"C:\Users\baron\Documents\Teach\615 Regression\Data")

# Read the data:

H = pd.read_csv("HOME_SALES.csv")

# To see the names of all variables in the data set:

H.columns
Out[47]:
Index(['ID', 'SALES_PRICE', 'FINISHED_AREA', 'BEDROOMS', 'BATHROOMS',
       'GARAGE_SIZE', 'YEAR_BUILT', 'STYLE', 'LOT_SIZE', 'AIR_CONDITIONER',
       'POOL', 'QUALITY', 'HIGHWAY'],
      dtype='object')
In [48]:
# Plot sales price against finished area:

plt.scatter(H["FINISHED_AREA"], H["SALES_PRICE"])
plt.xlabel("Finished Area")
plt.ylabel("Sales Price")
plt.show()
No description has been provided for this image
In [62]:
# That's familiar stuff so far. Now, we are fitting a regression model that we can use to predict 
# the house sales price based on its area. So, X = area, Y = price.

# `OLS` – conducts regression analysis and estimates the regression slope and intercept
# `add_constant` – adds the intercept term to the regression model
# `fittedvalues` – computes predicted values based on the obtained regression equation
# `plot` – plots these predicted values
    
# Fit the regression model:

X = sm.add_constant(H["FINISHED_AREA"])
reg = sm.OLS(H["SALES_PRICE"], X).fit()

# The estimated regression line can be added to the scatterplot:

plt.scatter(H["FINISHED_AREA"], H["SALES_PRICE"])

plt.plot(
    H["FINISHED_AREA"],
    reg.fittedvalues,
    linewidth=3
)

plt.xlabel("Finished Area")
plt.ylabel("Sales Price")
plt.show()
No description has been provided for this image
In [63]:
# The regression equation can also be obtained directly from the fitted model:

reg.params
Out[63]:
const           -81.432946
FINISHED_AREA     0.158950
dtype: float64
In [64]:
# Prediction. Predict the price for three houses that have the finished area of 2500, 4000, and 6000 square feet.
# Create a new data frame containing the three values of finished area:

new_houses = pd.DataFrame({
    "FINISHED_AREA": [2500, 4000, 6000]
})

# Add the intercept column:

new_houses = sm.add_constant(new_houses)

# Compute the predicted prices:

reg.predict(new_houses)
Out[64]:
0    315.942631
1    554.367977
2    872.268438
dtype: float64
In [65]:
# Inference. Use `summary()` to see results of the regression analysis.

# In Python, the equivalent of R's `summary(reg)` is:

print(reg.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:            SALES_PRICE   R-squared:                       0.672
Model:                            OLS   Adj. R-squared:                  0.671
Method:                 Least Squares   F-statistic:                     1063.
Date:                Sat, 29 Aug 2026   Prob (F-statistic):          8.28e-128
Time:                        22:09:42   Log-Likelihood:                -3021.3
No. Observations:                 522   AIC:                             6047.
Df Residuals:                     520   BIC:                             6055.
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
=================================================================================
                    coef    std err          t      P>|t|      [0.025      0.975]
---------------------------------------------------------------------------------
const           -81.4329     11.552     -7.049      0.000    -104.127     -58.739
FINISHED_AREA     0.1590      0.005     32.605      0.000       0.149       0.169
==============================================================================
Omnibus:                      145.431   Durbin-Watson:                   1.358
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              499.032
Skew:                           1.267   Prob(JB):                    4.33e-109
Kurtosis:                       7.065   Cond. No.                     7.90e+03
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 7.9e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
In [66]:
# The regression output includes:

# Estimates of the intercept and slope
# Standard errors
# t-statistics
# p-values
# R-squared and adjusted R-squared
# Residual standard error
# F-statistic and its p-value

# Conclusion: the sample regression equation is  Price = -81.4 + 0.159(area).

# The slope and the intercept are both significant. The area can actually be used as an important factor to predict the sales price. This variable alone explains 67.15% of the total variation of house sales prices.
In [67]:
# Analysis of Variance

# The ANOVA table for the regression can be obtained from the fitted model:

sm.stats.anova_lm(reg, typ=1)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[67], line 5
      1 # Analysis of Variance
      2 
      3 # The ANOVA table for the regression can be obtained from the fitted model:
----> 5 sm.stats.anova_lm(reg, typ=1)

File ~\AppData\Local\anaconda3\Lib\site-packages\statsmodels\stats\anova.py:353, in anova_lm(*args, **kwargs)
    351 if len(args) == 1:
    352     model = args[0]
--> 353     return anova_single(model, **kwargs)
    355 if typ not in [1, "I"]:
    356     raise ValueError("Multiple models only supported for type I. "
    357                      "Got type %s" % str(typ))

File ~\AppData\Local\anaconda3\Lib\site-packages\statsmodels\stats\anova.py:70, in anova_single(model, **kwargs)
     67 nobs = exog.shape[0]
     69 response_name = model.model.endog_names
---> 70 design_info = model.model.data.design_info
     71 exog_names = model.model.exog_names
     72 # +1 for resids

AttributeError: 'PandasData' object has no attribute 'design_info'
In [68]:
# What's the problem? `anova_lm()` expects a model created using the formula interface. 
# Therefore, for the ANOVA table, we will fit the same model using `statsmodels`' formula interface:

import statsmodels.formula.api as smf

reg_formula = smf.ols(
    "SALES_PRICE ~ FINISHED_AREA",
    data=H
).fit()

# Now obtain the ANOVA table:

sm.stats.anova_lm(reg_formula)

# The ANOVA table contains:

# Degrees of freedom (`df`)
# Sum of squares (`sum_sq`)
# Mean squares (`mean_sq`)
# F-statistic (`F`)
# p-value (`PR(>F)`)

# The ANOVA F-statistic is the same F-statistic reported in the regression summary. 
# For a simple linear regression with one predictor, the test of the regression slope 
# and the overall F-test are equivalent.
Out[68]:
df sum_sq mean_sq F PR(>F)
FINISHED_AREA 1.0 6.655486e+06 6.655486e+06 1063.103043 8.284610e-128
Residual 520.0 3.255426e+06 6.260434e+03 NaN NaN